import json
import secrets
import string
from json import JSONDecodeError

import aiofiles
import aiohttp
import pyuseragents
from aiohttp import ClientHttpProxyError, ClientProxyConnectionError, ContentTypeError

from app.bot.utils.capmonster.turnstile import TurnstileTask
from app.bot.utils.kopeechka.api import AsyncKopeechka
from app.bot.utils.first_mail.api import FirstMail
from app.bot.utils.kopeechka.schemas import MailboxGetEmail
from app.bot.utils.logger import log
from app.bot.utils.dropmail.api import Dropmail


class NoEmailException(Exception):
    pass


class CaptchaNotSolvedException(Exception):
    pass


class WLOReger:
    def __init__(
        self,
        capmonter_token: str,
        kopeechka_token: str = None,
        firstmail_token: str = None,
    ):
        self.session = aiohttp.ClientSession()
        self.session.headers.update(
            {
                "User-Agent": pyuseragents.random(),
                "Content-Type": "application/json",
                "Accept": "application/json, text/plain, */*",
            }
        )
        self.capmonter_token = capmonter_token
        self.kopeechka_token = kopeechka_token
        self.firstmail_token = firstmail_token

    async def _make_request(self, method: str, url: str, **kwargs) -> dict | str:
        async with await self.session.request(method, url, **kwargs) as response:
            try:
                return await response.json(content_type=None)
            except (JSONDecodeError, ContentTypeError):
                return await response.text()

    async def get_mail(
        self, temp_mail_token: str = None
    ) -> tuple[AsyncKopeechka | Dropmail, MailboxGetEmail, str | None] | tuple[
        AsyncKopeechka | Dropmail, str | None
    ]:
        if self.kopeechka_token:
            if "&" in self.kopeechka_token:
                mail_type = self.kopeechka_token.split("&")[1]
                self.kopeechka_token = self.kopeechka_token.split("&")[0]
            else:
                mail_type = "ALL"
            mail = AsyncKopeechka(self.kopeechka_token)
            new_mail = await mail.mailbox_get_email(
                site="wlo.link", sender="wlo", mail_type=mail_type, soft_id=4
            )
            email_address = new_mail.mail
            if email_address:
                log.info(f"Получил почту с копеечки {email_address}")
        else:
            mail = Dropmail(token=temp_mail_token)
            email_address = await mail.create_mail_box()
            if email_address:
                log.info(f"Получил временную почту {email_address}")

        if self.kopeechka_token:
            return mail, new_mail, email_address
        return mail, email_address

    async def solve_captcha(self) -> str | None | bool:

        log.info("Решаю капчу на WLO")

        capmonster = TurnstileTask(self.capmonter_token)

        try:
            # await capmonster.set_proxy(
            #     "http", "77.37.132.143", 10014, "socrobotic14", "socrobotic14r"
            # )
            task_id = await capmonster.create_task(
                "https://api-id.streamlabs.com/v1/auth/register",
                "0x4AAAAAAACELUBpqiwktdQ9",
            )
            log.info(f"Создал задачу по решению капчи {task_id}")

            result = await capmonster.join_task_result(task_id)
            captcha_result = result.get("token")

            log.info("Капча решена")

            return captcha_result

        except Exception as e:
            log.exception(f"Ошибка во время решения капчи: {str(e)}")
        finally:
            await capmonster.session.close()
        return False

    async def register_account(
        self,
        telegram_id: int,
        proxy_string: str,
    ) -> tuple[bool, bool, bool] | tuple[str | None, str, bool]:

        if "http://" not in proxy_string:
            proxy_string = f"http://{proxy_string}"

        url = "https://api-id.streamlabs.com/v1/auth/register"
        verurl = "https://api-id.streamlabs.com/v1/users/@me/email/verification/confirm"

        log.info("Регистрирую аккаунт WLO")

        alphabet = string.ascii_letters + string.digits
        password = "".join(secrets.choice(alphabet) for _ in range(20))
        log.info(f"Сгенерировал пароль: {password}")

        try:
            # Проверяем валидность прокси перед работой остального скрипта
            await self._make_request("get", url, proxy=proxy_string)
        except (ClientProxyConnectionError, ClientHttpProxyError, TimeoutError) as e:
            raise e

        if self.kopeechka_token:
            mail, new_mail, email_address = await self.get_mail(
                temp_mail_token=password
            )
        # TODO Ввести приоритет почт
        else:
            mail, email_address = await self.get_mail(temp_mail_token=password)

        if not email_address:
            raise NoEmailException

        try:

            captcha_result = await self.solve_captcha()

            if not captcha_result:
                raise CaptchaNotSolvedException

            data = {
                "agree": True,
                "captcha_token": captcha_result,
                "email": email_address,
                "locale": "ru-RU",
                "password": password,
                "username": "",
            }

            register_resp = await self._make_request(
                "post", url, json=data, proxy=proxy_string
            )
            log.info(register_resp)

            if register_resp or not register_resp.get("message"):
                log.info("Зарегистрировал аккаунт WLO")

                if not isinstance(mail, AsyncKopeechka):
                    code = await mail.get_code_from_temp_mail()
                else:
                    code = await mail.get_code_from_mail(full=1, email_id=new_mail.id)

                if code:
                    data = {"email": email_address, "code": code, "tfa_code": ""}

                    verif_resp = await self._make_request(
                        "post", verurl, json=data, proxy=proxy_string
                    )

                    if not verif_resp:
                        log.info(f"Аккаунт WLO {email_address}:{password} подтвержден!")

                        return email_address, password, True
                    else:
                        # TODO Вынести в отдельную функцию
                        async with aiofiles.open(
                            f"app/bot/responses/{telegram_id}_verif_resp.html", "w"
                        ) as f:
                            if isinstance(verif_resp, str):
                                await f.write(verif_resp)
                            else:
                                await f.write(json.dumps(verif_resp))
                        log.error(f"Ошибка при верификации аккаунта {email_address}")
                else:
                    log.info(f"Не удалось подтвердить почту {email_address}")
                    return email_address, password, False
            else:
                # TODO Вынести в отдельную функцию
                async with aiofiles.open(
                    f"app/bot/responses/{telegram_id}_register_resp.html", "w"
                ) as f:
                    if isinstance(register_resp, str):
                        await f.write(register_resp)
                    else:
                        await f.write(json.dumps(register_resp))
                log.error(f"Ошибка при регистрации аккаунта {email_address}")

        except Exception as e:
            log.exception(e)
        finally:
            if isinstance(mail, Dropmail):
                await mail.session.close()
        return False, False, False
